home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Info-Mac 4
/
Info_Mac IV CD-ROM (Pacific HiTech Inc.)(August 1994).iso
/
Development
/
Source
/
Telnet 2.6.1d1 4⁄26⁄94 Folder
/
source
/
main
/
parse.c
< prev
next >
Wrap
Text File
|
1994-02-20
|
46KB
|
1,432 lines
/****************************************************************
* NCSA Telnet for the Macintosh *
* *
* National Center for Supercomputing Applications *
* Software Development Group *
* 152 Computing Applications Building *
* 605 E. Springfield Ave. *
* Champaign, IL 61820 *
* *
* Copyright (c) 1986-1992, *
* Board of Trustees of the University of Illinois *
****************************************************************/
#ifdef MPW
#pragma segment 4
#endif
#include <stdio.h>
#include <string.h>
#include "TelnetHeader.h"
#include "parse.h" // For our #defines
#include "wind.h" /* For WindRec structure */
#include "network.proto.h" /* For net functions */
#include "debug.h" /* For putln proto */
#include "vgtek.proto.h"
#include "vsdata.h"
#include "vsinterf.proto.h"
#include "maclook.proto.h"
#include "tekrgmac.proto.h"
#include "menuseg.proto.h"
#include "vr.h"
#include "vr.proto.h"
#include "encrypt.proto.h"
#include "kerberos.proto.h"
#include "wdefpatch.proto.h"
//#define OPTS_DEBUG
#ifdef OPTS_DEBUG
#define opts_debug_print(x) putln(x)
#include "optsdebug.h"
#else
#define opts_debug_print(x)
#endif
#define SEND_NOSUPPORT_ON_SLC_INIT 1
extern short scrn;
extern WindRec *screens;
#include "parse.proto.h"
/*********************************************************************/
/* parse
* look at the string which has just come in from outside and
* check for special sequences that we are interested in.
*
* Tries to pass through routine strings immediately, waiting for special
* characters ESC and 255 to change modes.
*/
#ifdef notdef
void parse (struct WindRec *tw, unsigned char *st, short cnt)
{
short j, l;
unsigned char *cp, ebuf[256];
if (tw && tw->decrypt_input) {
while (cnt > 0) {
l = j = ((cnt > sizeof(ebuf))? sizeof(ebuf) : cnt);
cp = ebuf;
while (j-- > 0)
*cp++ = (*tw->decrypt_input)(tw, (int)(*st++));
parse2(tw, ebuf, l);
cnt -= l;
}
} else {
parse2(tw, st, cnt);
}
}
#endif
void parse (struct WindRec *tw, unsigned char *st, short cnt)
{
short i,temptw;
unsigned char *mark,*orig;
#ifdef OPTS_DEBUG
char munger[255];
#endif
unsigned char *cp;
char nullbuf[] = {AUTH_NULL, AUTH_CLIENT_TO_SERVER|AUTH_HOW_ONE_WAY};
orig = st; /* remember beginning point */
mark = st + cnt; /* set to end of input string */
/*
* raw mode for debugging, passes through escape sequences and other
* special characters as <27> symbols
*/
if (tw->termstate == DUMBTYPE)
{
for (i=0; i < cnt; i++,st++) /* put on screen raw */
if (*st == 27 || *st > 126 && !(tw->ftpstate && gFTPServerPrefs->DoISOtranslation))
{
sprintf((char *)tw->parsedat,"<%d>",*st);
VSwrite(tw->vs,(char *)tw->parsedat,strlen((char *)tw->parsedat)); /* send to virtual screen */
}
else
VSwrite(tw->vs,(char *) st,1); /* BYU LSC */
}
else
{
/*
* traverse string, looking for any special characters which indicate that
* we need to change modes.
*/
while (st < mark)
{
switch (tw->telstate)
{
case GS:
case ESCFOUND:
if (tw->tektype >= 0) { /* we'll allow the TEK */
if ((*st == 12) || (tw->telstate == GS)) { /* esc-FF */
if ((*st == 12) &&
((tw->termstate == VTEKTYPE) || (!tw->tekclear))) {
if (tw->termstate == VTEKTYPE)
putln("Entering Tek mode");
else if (tw->curgraph > -1)
detachGraphics(tw->curgraph);
if (tw->curgraph <= -1) { // No current TEK window
temptw = VGnewwin(1,tw->vs);
if (temptw > -1) {
Str255 scratchPstring;
tw->curgraph = temptw;
VGgiveinfo(temptw);
GetWTitle(tw->wind, scratchPstring);
PtoCstr(scratchPstring);
RGattach(temptw,tw->vs,(char *)scratchPstring, tw->tektype);
}
else
tw->telstate = STNORM; // Can't create TEK window
}
if (tw->telstate != STNORM)
tw->termstate = TEKTYPE;
}
if (tw->telstate == GS) {
st++;
VGwrite(tw->curgraph,"\035",1);
}
else if (tw->telstate != STNORM)
VGwrite(tw->curgraph,"\037\033\014",3);
tw->telstate = STNORM;
break;
} // FF or GS
} // tw->tektype >= 0
if (*st == '^') { /* ESC- ^ */
tw->termstate = RASTYPE;
tw->telstate = STNORM;
VRwrite("\033^",2); /* Put it through */
orig = ++st;
break;
}
if (tw->termstate == TEKTYPE)
VGwrite(tw->curgraph,"\033",1);
else if (tw->termstate == RASTYPE)
VRwrite("\033",1);
else
VSwrite(tw->vs,"\033",1); /* send the missing ESC */
tw->telstate = STNORM;
break;
/*------------------------------------------------------------------------------*
* IACFOUND: This is the start of the Telnet option negotiation. If Telnet *
* gets an IAC character, then negotiation data follows, and is ready to be *
* parsed. *
*------------------------------------------------------------------------------*/
case IACFOUND: /* telnet option negotiation- START */
if (*st == 255) { /* real data = 255 */
orig = st; // MP: translation mod (break will make it miss
// this assignment later on in the case, Jim!)
st++; /* real 255 will get sent */
tw->telstate = STNORM;
break;
}
if ( 239 < *st ) {
tw->telstate = *st; /* by what the option is */
st++;
break;
}
tw->telstate = STNORM;
orig=st;
break;
case TEL_EOF: /* BYU LSC */
#ifdef OPTS_DEBUG
sprintf(munger,"RECV: %s",telstates[tw->telstate - TEL_SE]);
opts_debug_print(munger);
#endif
orig=st;
tw->telstate=STNORM;
break;
case TEL_EL: /* thanx Quincey!!! */
case TEL_EC:
case TEL_AYT:
case TEL_AO:
case TEL_IP:
case TEL_BREAK:
case TEL_DM:
case TEL_NOP:
case TEL_SE:
#ifdef OPTS_DEBUG
sprintf(munger,"RECV: %s",telstates[tw->telstate - TEL_SE]);
opts_debug_print(munger);
#endif
tw->telstate = STNORM;
orig=st;
case TEL_GA:
orig=st;
tw->telstate = STNORM;
break;
/*------------------------------------------------------------------------------*
* Negotiate DOTEL: sent by the server whenever it wants the client to do *
* an option *
*------------------------------------------------------------------------------*/
case TEL_DOTEL:
#ifdef OPTS_DEBUG
sprintf(munger,"RECV: %s %s",telstates[tw->telstate-TEL_SE],teloptions[*st]);
opts_debug_print(munger);
#endif
switch( *st)
{
case N_SGA: /* Sure we'll supress GA */
if (!tw->Isga) {
tw->Isga=1;
sprintf((char *)tw->parsedat,"%c%c%c",255,TEL_WILLTEL,*st);
netpush(tw->port);
netwrite(tw->port,tw->parsedat,3);
}
#ifdef OPTS_DEBUG
sprintf(munger,"SENT: WILL %s",teloptions[*st]);
opts_debug_print(munger);
#endif
tw->telstate = STNORM;
orig = ++st;
break;
case N_TERMTYP: /* And we'll even tell you about ourselves */
if (!tw->Ittype) {
tw->Ittype=1;
sprintf((char *)tw->parsedat,"%c%c%c",255,TEL_WILLTEL,*st);
netpush(tw->port);
netwrite(tw->port,tw->parsedat,3);
}
#ifdef OPTS_DEBUG
sprintf(munger,"SENT: WILL %s",teloptions[*st]);
opts_debug_print(munger);
#endif
tw->telstate = STNORM;
orig = ++st;
break;
case N_NAWS: /* NCSA: sure, I like changing the window size! */
tw->naws =1; /* NCSA: this session is now NAWS */
sprintf((char *)tw->parsedat,"%c%c%c",255,TEL_WILLTEL,*st); /* NCSA: reply, we will to NAWS */
netpush(tw->port); /* NCSA */
netwrite(tw->port,tw->parsedat,3); /* NCSA: send it out */
#ifdef OPTS_DEBUG
sprintf(munger,"SENT: WILL %s",teloptions[*st]);
opts_debug_print(munger);
#endif
SendNAWSinfo(tw, tw->width, tw->rows);
// sprintf((char *)tw->parsedat,"%c%c%c%c%c%c%c%c%c",IAC,TEL_SB, /* BYU 2.4.16 */
// N_NAWS,(char)0,(unsigned char)tw->width, /* BYU 2.4.16 */
// (char)0,(unsigned char)tw->rows,IAC,TEL_SE); /* BYU 2.4.16 */
// netpush(tw->port); /* BYU 2.4.16 */
// netwrite(tw->port,tw->parsedat,9); /* BYU 2.4.16 */
#ifdef OPTS_DEBUG
opts_debug_print("SENT: IAC TEL_SB N_NAWS <data> IAC TEL_SE");
#endif
tw->telstate = STNORM; /* NCSA */
orig = ++st; /* NCSA */
break; /* NCSA */
case N_LINEMODE: /* Sure I'll do line mode... */
if (tw->lineAllow) {
sprintf((char *)tw->parsedat,"%c%c%c",IAC,TEL_WILLTEL,*st++);
netwrite(tw->port,tw->parsedat,3);
#ifdef OPTS_DEBUG
sprintf(munger,"SENT: WILL %s",teloptions[*st]);
opts_debug_print(munger);
#endif
sprintf((char *)tw->parsedat,"%c%c%c%c",IAC,TEL_SB,N_LINEMODE,L_SLC);
netwrite(tw->port,tw->parsedat,4);
#ifdef OPTS_DEBUG
opts_debug_print("SENT: IAC SB LINEMODE SLC");
#endif
for (i=1; i<= SLC_MAX; i++){
if (tw->slc[i]==-1) {
#ifdef SEND_NOSUPPORT_ON_SLC_INIT
sprintf((char *)tw->parsedat,"%c%c%c",i,SLC_NOSUPPORT,0);
#ifdef OPTS_DEBUG
sprintf(munger," %s NO_SUPPORT 0",LMoptions[i]);
#endif
#endif
}
else
{
sprintf((char *)tw->parsedat,"%c%c%c",i,SLC_CANTCHANGE,(char)tw->slc[i]);
#ifdef OPTS_DEBUG
sprintf(munger," %s CANTCHANGE %i",LMoptions[i],(int)tw->slc[i]);
#endif
}
opts_debug_print(munger);
netwrite(tw->port,tw->parsedat,3);
}
opts_debug_print("SENT: IAC SE");
sprintf((char *)tw->parsedat,"%c%c",IAC,TEL_SE);
netwrite(tw->port,tw->parsedat,2);
}
else {
sprintf((char *)tw->parsedat,"%c%c%c",IAC,TEL_WONTTEL,*st++);
opts_debug_print("SENT: WONT Linemode");
netwrite(tw->port,tw->parsedat,3);
}
break;
case N_AUTHENTICATION: /* do auth */
if (!tw->myopts[OPT_AUTHENTICATION-MHOPTS_BASE]) {
if (tw->authenticate) {
(tw->myopts)[OPT_AUTHENTICATION-MHOPTS_BASE] = 1;
sprintf((char *)tw->parsedat,"%c%c%c",IAC,TEL_WILLTEL,*st);
netwrite(tw->port,tw->parsedat,3);
#ifdef OPTS_DEBUG
sprintf(munger,"SENT: WILL %s",teloptions[*st]);
opts_debug_print(munger);
#endif
} else {
sprintf((char *)tw->parsedat,"%c%c%c",IAC,TEL_WONTTEL,*st);
netwrite(tw->port,tw->parsedat,3);
#ifdef OPTS_DEBUG
sprintf(munger,"SENT: WONT %s",teloptions[*st]);
opts_debug_print(munger);
#endif
}
}
tw->telstate = STNORM;
orig = ++st;
break;
case N_ENCRYPT: /* do encrypt */
if (!tw->myopts[OPT_ENCRYPT-MHOPTS_BASE]) {
if (tw->encrypt) {
(tw->myopts)[OPT_ENCRYPT-MHOPTS_BASE] = 1;
sprintf((char *)tw->parsedat,"%c%c%c",IAC,TEL_WILLTEL,*st);
netwrite(tw->port,tw->parsedat,3);
#ifdef OPTS_DEBUG
sprintf(munger,"SENT: WILL %s",teloptions[*st]);
opts_debug_print(munger);
#endif
} else {
sprintf((char *)tw->parsedat,"%c%c%c",IAC,TEL_WONTTEL,*st);
netwrite(tw->port,tw->parsedat,3);
#ifdef OPTS_DEBUG
sprintf(munger,"SENT: WONT %s",teloptions[*st]);
opts_debug_print(munger);
#endif
}
}
tw->telstate = STNORM;
orig = ++st;
break;
default: /* But, we won't do .... */
sprintf((char *)tw->parsedat,"%c%c%c",255,TEL_WONTTEL,*st++);
netwrite(tw->port,tw->parsedat,3);
#ifdef OPTS_DEBUG
sprintf(munger,"SENT: WONT %s",teloptions[*(st-1)]);
opts_debug_print(munger);
#endif
break;
}
tw->telstate = STNORM;
orig = st;
break;
/*------------------------------------------------------------------------------*
* Negotiate DONTTEL: sent by the server whenever it wants the client to *
* definitely NOT do an option. Sent to prevent client from negotiating an *
* unsupported option *
*------------------------------------------------------------------------------*/
case TEL_DONTTEL:
#ifdef OPTS_DEBUG
sprintf(munger,"RECV: %s %s",telstates[tw->telstate-TEL_SE],teloptions[*st]);
opts_debug_print(munger);
#endif
tw->telstate = STNORM;
switch (*st++) {
case N_ENCRYPT: /* dont encrypt */
case N_AUTHENTICATION: /* dont authenticate */
tw->myopts[*(st-1)-MHOPTS_BASE] = 0;
sprintf((char *)tw->parsedat,"%c%c%c", IAC, TEL_WONTTEL, *(st-1));
netpush(tw->port);
netwrite(tw->port,tw->parsedat,3); /* refuse it */
#ifdef OPTS_DEBUG
sprintf(munger,"SENT: WONT %s", teloptions[*(st-1)]);
opts_debug_print(munger);
#endif
break;
}
orig = st;
break;
/*------------------------------------------------------------------------------*
* Negotiate WILLTEL: sent by the client to try and get the server to use an *
* option. This tells the server that the client is requesting that an option *
* be used *
*------------------------------------------------------------------------------*/
case TEL_WILLTEL:
#ifdef OPTS_DEBUG
sprintf(munger,"RECV: %s %s",telstates[tw->telstate-TEL_SE],teloptions[*st]);
opts_debug_print(munger);
#endif
tw->telstate = STNORM;
switch(*st++)
{
case N_ECHO: /* Echo on the other end*/
#ifdef OPTS_DEBUG
if (!tw->echo)
opts_debug_print("tw->echo is False.");
#endif
if (!tw->echo)
break;
tw->echo = 0; /* Ok, in that case they can echo... */
changeport(scrn,scrn);
sprintf((char *)tw->parsedat,"%c%c%c",IAC,TEL_DOTEL,1);
netpush(tw->port);
netwrite(tw->port,tw->parsedat,3); /* refuse it */
#ifdef OPTS_DEBUG
sprintf(munger,"SENT: DO %s",teloptions[*(st-1)]);
opts_debug_print(munger);
#endif
break;
case N_SGA: /* Supress GA */
#ifdef OPTS_DEBUG
if (tw->Usga)
opts_debug_print("tw->Usga is True.");
#endif
if (tw->Usga)
break;
tw->Usga = 1; /* Go Ahead and supress GA */
sprintf((char *)tw->parsedat,"%c%c%c",IAC,TEL_DOTEL,3);
netpush(tw->port);
netwrite(tw->port,tw->parsedat,3); /* refuse it */
#ifdef OPTS_DEBUG
sprintf(munger,"SENT: DO %s",teloptions[*(st-1)]);
opts_debug_print(munger);
#endif
break;
case N_TIMING: /* Timing Mark */
tw->timing = 0;
break;
case N_AUTHENTICATION: /* will auth */
if (!tw->hisopts[OPT_AUTHENTICATION-MHOPTS_BASE]) {
if (tw->authenticate) {
(tw->hisopts)[OPT_AUTHENTICATION-MHOPTS_BASE] = 1;
sprintf((char *)tw->parsedat,"%c%c%c",IAC,TEL_DOTEL,OPT_AUTHENTICATION);
netwrite(tw->port,tw->parsedat,3);
#ifdef OPTS_DEBUG
sprintf(munger,"SENT: WILL %s",teloptions[OPT_AUTHENTICATION]);
opts_debug_print(munger);
#endif
} else {
sprintf((char *)tw->parsedat,"%c%c%c",IAC,TEL_DONTTEL,OPT_AUTHENTICATION);
netwrite(tw->port,tw->parsedat,3);
#ifdef OPTS_DEBUG
sprintf(munger,"SENT: WONT %s",teloptions[OPT_AUTHENTICATION]);
opts_debug_print(munger);
#endif
}
}
break;
case N_ENCRYPT: /* will encrypt */
if (!tw->hisopts[OPT_ENCRYPT-MHOPTS_BASE]) {
if (tw->encrypt) {
(tw->hisopts)[OPT_ENCRYPT-MHOPTS_BASE] = 1;
sprintf((char *)tw->parsedat,"%c%c%c",IAC,TEL_DOTEL,OPT_ENCRYPT);
netwrite(tw->port,tw->parsedat,3);
#ifdef OPTS_DEBUG
sprintf(munger,"SENT: DO %s",teloptions[OPT_ENCRYPT]);
opts_debug_print(munger);
#endif
} else {
sprintf((char *)tw->parsedat,"%c%c%c",IAC,TEL_DONTTEL,OPT_ENCRYPT);
netwrite(tw->port,tw->parsedat,3);
#ifdef OPTS_DEBUG
sprintf(munger,"SENT: DONT %s",teloptions[OPT_ENCRYPT]);
opts_debug_print(munger);
#endif
}
}
if (tw->authenticate && tw->encrypt) /* do this here (and tn3270?) ddd */
encrypt_send_support(tw->edata);
break;
default:
sprintf((char *)tw->parsedat,"%c%c%c",IAC,TEL_DONTTEL,*(st-1));
netwrite(tw->port,tw->parsedat,3); /* refuse it */
#ifdef OPTS_DEBUG
sprintf(munger,"SENT: DONT %s",teloptions[*(st-1)]);
opts_debug_print(munger);
#endif
}
orig = st;
break;
/*------------------------------------------------------------------------------*
* Negotiate WONTTEL: The client refuses a Telnet option, and wants the *
* to forget about trying to negotiate it. *
*------------------------------------------------------------------------------*/
case TEL_WONTTEL:
#ifdef OPTS_DEBUG
sprintf(munger,"?SENT: (WONTTEL)%s %s",telstates[tw->telstate-TEL_SE],teloptions[*st]);
opts_debug_print(munger);
#endif
tw->telstate = STNORM;
switch(*st++)
{ /* which option? */
case N_ECHO: /* echo */
if (tw->echo)
break;
tw->echo = 1; /* Ok, I will echo if I have to... */
changeport(scrn,scrn);
sprintf((char *)tw->parsedat,"%c%c%c",IAC,TEL_DONTTEL,N_ECHO);
netpush(tw->port);
netwrite(tw->port,tw->parsedat,3); /* refuse it */
#ifdef OPTS_DEBUG
sprintf(munger,"SENT: %s %s",telstates[TEL_WONTTEL-TEL_SE],teloptions[*(st-1)]);
opts_debug_print(munger);
#endif
break;
case N_SGA:
if (!tw->Usga)
break;
tw->Usga = 0;
sprintf((char *)tw->parsedat,"%c%c%c",IAC,TEL_DONTTEL,N_SGA);
netpush(tw->port);
netwrite(tw->port,tw->parsedat,3); /* refuse it */
#ifdef OPTS_DEBUG
sprintf(munger,"SENT: %s %s",telstates[TEL_WONTTEL-TEL_SE],teloptions[*(st-1)]);
opts_debug_print(munger);
#endif
break;
case N_TIMING: /* Timing Mark */
tw->timing = 0;
break;
case N_ENCRYPT: /* wont encrypt */
case N_AUTHENTICATION: /* wont authenticate */
tw->hisopts[*(st-1)-MHOPTS_BASE] = 0;
sprintf((char *)tw->parsedat,"%c%c%c",IAC,TEL_DONTTEL,*(st-1));
netpush(tw->port);
netwrite(tw->port,tw->parsedat,3); /* refuse it */
#ifdef OPTS_DEBUG
sprintf(munger,"SENT: WONT %s", teloptions[*(st-1)]);
opts_debug_print(munger);
#endif
break;
default:
break;
}
orig = st;
break;
/*------------------------------------------------------------------------------*
* SUBNEGOTIATION -- If there is an SB token found, then Telnet needs to do *
* some subnegotiating. The subnegotiation data follows, and needs to be put *
* somewhere safe. Make sure and update the state, so that we know that *
* Telnet is doing some subnegotiations and not just horsing around *
*------------------------------------------------------------------------------*/
case TEL_SB:
tw->telstate = NEGOTIATE; /* Guess what I'm doing... */
orig=st;
substate=0; /* Defined for each */
tw->parseIndex =0; /* No data yet! Clear any possible garbage */
break;
case NEGOTIATE:
if (substate <200) {
switch( *st) {
case IAC: /* is it the famous DOUBLE-IAC??? */
if (*(st+1) ==IAC) /* Yes, treat as data value 255 */
{
tw->parsedat[tw->parseIndex++]=*st++;
/*tw->parsedat[tw->parseIndex++]=* */ st++;
}
else /* otherwise just save it */
{
tw->parsedat[tw->parseIndex]='\0';
substate=*st++;
}
break;
default:
tw->parsedat[tw->parseIndex++]=*st++;
break;
}
} else
{
switch( substate) /* subnegotiate */
{
case IAC:
substate=*st++;
if (substate==TEL_SE) {
switch( tw->parsedat[0])
{
/*------------------------------------------------------------------------------*
* SUBNegotiate Termtype: send the term type data now *
*------------------------------------------------------------------------------*/
case N_TERMTYP:
if (tw->parsedat[1]==1)
{
char s[255], termtmp[40];
BlockMove(tw->answerback, termtmp, 32);
PtoCstr((StringPtr)termtmp);
#ifdef OPTS_DEBUG
sprintf(munger,"RECV: SB TERMINAL-TYPE SEND\r\nSEND: SB TERMINAL-TYPE IS %s\r\n",termtmp);
opts_debug_print(munger);
#endif
netpush(tw->port);
netwrite(tw->port,"\377\372\030\000",4);
netpush(tw->port);
sprintf(s,"%s\377\360",termtmp);
netwrite(tw->port, s, strlen(s));
}
break;
/*------------------------------------------------------------------------------*
* SUBNegotiate ENCRYPTION: *
*------------------------------------------------------------------------------*/
case N_ENCRYPT: {
unsigned char *subpointer = &tw->parsedat[SB_TYPE];
long sublen = &tw->parsedat[tw->parseIndex] -
subpointer;
#ifdef OPTS_DEBUG
{
short j;
char *cp = munger;
sprintf(cp,"RECV: SB ENCRYPT %02X ",
tw->parsedat[SB_SUBOPTION]);
cp += strlen(cp);
for (j = 0; j < sublen; j++) {
sprintf(cp, "%02X ", subpointer[j] & 0xff);
cp += strlen(cp);
}
sprintf(cp, "\r\n");
opts_debug_print(munger);
}
#endif
if (tw->edata != NULL)
netportencryptstate(tw->port, (Ptr)tw->edata);
switch (tw->parsedat[SB_SUBOPTION]) {
case ENCRYPT_START:
if (!tw->hisopts[OPT_ENCRYPT-MHOPTS_BASE]) /* my_want_state_is_dont(tw->o_encrypt) */
break;
encrypt_start(tw->edata, subpointer, sublen);
/*
* If we turned on decryption we must
* decrypt the remainder of the buffer
*/
if (tw->edata->decrypt_input) {
unsigned char *cp = st;
while (cp < mark) {
*cp = (*tw->edata->decrypt_input)(tw->edata, (int)(*cp));
cp++;
}
netportencryptstate(tw->port, (Ptr)tw->edata);
}
break;
case ENCRYPT_END:
if (!tw->hisopts[OPT_ENCRYPT-MHOPTS_BASE]) /* if my_want_state_is_dont(tw->o_encrypt) */
break;
encrypt_end(tw->edata);
break;
case ENCRYPT_SUPPORT:
if (!tw->myopts[OPT_ENCRYPT-MHOPTS_BASE]) /* if my_want_state_is_wont(tw->o_encrypt) */
break;
encrypt_support(tw->edata, subpointer, sublen);
break;
case ENCRYPT_REQSTART:
if (!tw->myopts[OPT_ENCRYPT-MHOPTS_BASE]) /* if my_want_state_is_wont(tw->o_encrypt) */
break;
encrypt_request_start(tw->edata, subpointer, sublen);
break;
case ENCRYPT_REQEND:
if (!tw->myopts[OPT_ENCRYPT-MHOPTS_BASE]) /* if my_want_state_is_wont(tw->o_encrypt) */
break;
/*
* We can always send an REQEND so that
* we cannot get stuck encrypting. We
* should only get this if we have been
* able to get in the correct mode
* anyhow.
*/
encrypt_request_end(tw->edata);
break;
case ENCRYPT_IS:
if (!tw->hisopts[OPT_ENCRYPT-MHOPTS_BASE]) /* if my_want_state_is_dont(tw->o_encrypt) */
break;
encrypt_is(tw->edata, subpointer, sublen);
break;
case ENCRYPT_REPLY:
if (!tw->myopts[OPT_ENCRYPT-MHOPTS_BASE]) /* if my_want_state_is_wont(tw->o_encrypt) */
break;
encrypt_reply(tw->edata, subpointer, sublen);
break;
case ENCRYPT_ENC_KEYID:
if (!tw->hisopts[OPT_ENCRYPT-MHOPTS_BASE]) /* if my_want_state_is_dont(tw->o_encrypt) */
break;
encrypt_enc_keyid(tw->edata, subpointer, sublen);
break;
case ENCRYPT_DEC_KEYID:
if (!tw->myopts[OPT_ENCRYPT-MHOPTS_BASE]) /* if my_want_state_is_wont(tw->o_encrypt) */
break;
encrypt_dec_keyid(tw->edata, subpointer, sublen);
break;
default:
break;
}
}
break;
/*------------------------------------------------------------------------------*
* SUBNegotiate Authentication: send the authentication data now *
*------------------------------------------------------------------------------*/
case N_AUTHENTICATION:
#ifdef OPTS_DEBUG2
{
short j;
char *cp = munger;
char *subpointer = &tw->parsedat[SB_TYPE];
long sublen = &tw->parsedat[tw->parseIndex] -
subpointer;
sprintf(cp,"RECV: SB AUTH %02X ",
tw->parsedat[SB_SUBOPTION]);
cp += strlen(cp);
for (j = 0; j < sublen; j++) {
sprintf(cp, "%02X ", subpointer[j] & 0xff);
cp += strlen(cp);
}
sprintf(cp, "\r\n");
opts_debug_print(munger);
}
#endif
switch (tw->parsedat[SB_SUBOPTION]) {
case TNQ_IS:
break;
case TNQ_SEND:
/*
* For telnet clients.
* The buffer contains:
* AUTHENTICATION SEND type modifier
* [type modifier] [...]
* Scan the type/modifier pairs until we
* find one we can do. Since they are are
* in priority order, the first one we
* find that we can do wins.
*/
cp = &tw->parsedat[SB_TYPE];
for (; cp < &tw->parsedat[tw->parseIndex];
cp += 2) {
switch (*cp) {
case AUTH_KERBEROS_V4:
if (krb_telnet(tw, (char *)cp, true)) {
/*
* if krb_telnet fails, send null authentication
* to avoid hanging.
*/
tn_sendsub(tw, N_AUTHENTICATION, TNQ_IS,
nullbuf, sizeof(nullbuf));
}
goto xx1;
}
}
/*
* If we can't do any of the requested
* authorizations, send AUTH_NULL.
*/
tn_sendsub(tw, N_AUTHENTICATION, TNQ_IS,
nullbuf, sizeof(nullbuf));
xx1:
break;
case TNQ_REPLY:
/*
* This is a reply to information we sent
* in a previous IS AUTH or CHALLENGE
* command. The buffer contains:
* AUTHENTICATION REPLY type modifier
* auth-data-type [auth data bytes]
*/
switch (tw->parsedat[SB_TYPE] & 0xFF) {
case AUTH_KERBEROS_V4:
tn_kerberos_reply(tw, (unsigned char *)tw->parsedat);
break;
default:
;
/* should we do somthing with an
unknown reply type ddd */
}
break;
case TNQ_NAME:
/*
* For the telnet server. This is the
* name that the telnet client
* wants us to use.
*/
break;
} /* switch tw->parsedat[SB_SUBOPTION] */
break;
/*------------------------------------------------------------------------------*
* SUBNegotiate Linemode: set up local characters, modes, and such *
*------------------------------------------------------------------------------*/
case N_LINEMODE:
switch(tw->parsedat[1])
{
char s[80];
case L_MODE: /* change mode */
#ifdef OPTS_DEBUG
strcpy(s, "RECV: SB LINEMODE MODE => ");
DemangleLineModeShort(s, tw->parsedat[2]);
opts_debug_print(s);
#endif
if (tw->lineAllow) { // First make sure we allowed linemode in the first place.
// RFC 1184 says client should ignore MODE negotiations with the MODE_ACK bit set, and should not
// generate a response if the negotiated MODE matches the current MODE
if (!((tw->parsedat[2] & L_MODE_ACK) || ((tw->parsedat[2] & L_MODE_MASK) == tw->lmode))) {
// This is a hack. Accept the state of L_EDIT and L_TRAPSIG that the server wants. If
// the server only wants zero, one, two or both of those bits, generate an ack. Otherwise
// send the server a mode that masks out all requested bits except EDIT and TRAPSIG.
// (Now, since we only support L_EDIT and/or L_TRAPSIG, if those are the only modes requested,)
// (send an ACK of that MODE to the server.)
tw->lmode = (tw->parsedat[2] & (L_EDIT | L_TRAPSIG)); // Accept the mode.
if ((tw->parsedat[2] & (L_EDIT | L_TRAPSIG)) == tw->parsedat[2]) {
tw->parsedat[2] |= L_MODE_ACK; // Set the MODE_ACK bit
}
// We got a MODE bit we dont support, mask out just what we support and send it back, UNacked.
else {
tw->parsedat[2] = tw->parsedat[2] & (L_EDIT | L_TRAPSIG);
}
sprintf(s,"%c%c%c%c",IAC,TEL_SB,N_LINEMODE,L_MODE);
netwrite(tw->port,s,4);
sprintf(s,"%c%c%c",tw->parsedat[2],IAC,TEL_SE);
netwrite(tw->port,s,3);
#ifdef OPTS_DEBUG
opts_debug_print("SENT: IAC SB");
strcpy(s, "SENT: LM MODE = ");
DemangleLineModeShort(s, tw->parsedat[2]);
opts_debug_print(s);
opts_debug_print("SENT: IAC SE");
#endif
}
#ifdef OPTS_DEBUG
else {
strcpy(s, "LINEMODE MODE = ");
DemangleLineModeShort(s, tw->parsedat[2]);
opts_debug_print(s);
if (tw->parsedat[2] & L_MODE_ACK)
opts_debug_print("\tignored 'cause MODE_ACK was set.");
else
opts_debug_print("\tIMPLICITLY ACCEPTED.");
strcpy(s, "Curr Linemode = ");
DemangleLineModeShort(s, tw->lmode);
opts_debug_print(s);
}
#endif
}
break;
case TEL_DOTEL:
#ifdef OPTS_DEBUG
sprintf(munger,"RECV: SB LINEMODE DO %c", tw->parsedat[2]);
opts_debug_print(munger);
#endif
netwrite(tw->port,"\377\372\042",3);
sprintf(s,"%c\002\377\360",TEL_WONTTEL);
opts_debug_print("SENT: IAC SB LINEMODE WONT FORWARDMASK IAC SE");
netwrite(tw->port,s,strlen(s));
break;
case TEL_WILLTEL:
#ifdef OPTS_DEBUG
sprintf(munger,"RECV: SB LINEMODE WILL %c", tw->parsedat[2]);
opts_debug_print(munger);
#endif
netwrite(tw->port,"\377\372\042",3);
sprintf(s,"%c\002\377\360",TEL_DONTTEL);
opts_debug_print("SENT: IAC SB LINEMODE DONT FORWARDMASK IAC SE");
netwrite(tw->port,s,strlen(s));
break;
case L_SLC: /* set local chars */
{
short lmslcflag = 0;
#ifdef OPTS_DEBUG
sprintf(munger,"RECV: SB LINEMODE SLC");
opts_debug_print(munger);
for(i=2;(tw->parsedat[i]!='\0') && (tw->parsedat[i]!=IAC); i+=3) {
if(tw->parsedat[i+1] & SLC_AWK)
sprintf(munger," %s %s|AWK %d",LMoptions[tw->parsedat[i]],LMflags[tw->parsedat[i+1] & SLC_LEVELBITS],tw->parsedat[i+2]);
else
sprintf(munger," %s %s %d",LMoptions[tw->parsedat[i]],LMflags[tw->parsedat[i+1] & SLC_LEVELBITS],tw->parsedat[i+2]);
opts_debug_print(munger);
// 2.6b16.1 if ((unsigned char)(tw->parsedat[i+2])==IAC) i++;
} /* end for */
#endif
for (i=2, lmslcflag=0; (tw->parsedat[i]!='\0') && (tw->parsedat[i]!=IAC); i+=3) {
// If func = 0, skip it 'cause we are the client.
// if (tw->parsedat[i] == 0)
// continue;
// If it's a function we don't know about, say we don't support it. If the server is telling
// us he doesn't support it, just ignore him.
if (tw->parsedat[i] > SLC_MAX) {
if ((tw->parsedat[i+1] & SLC_LEVELBITS) != SLC_NOSUPPORT) {
if (!lmslcflag) {
lmslcflag = 1; // Do this only once
sprintf(s,"%c%c%c%c",IAC,TEL_SB,N_LINEMODE,L_SLC);
netwrite(tw->port,s,4);
opts_debug_print("SENT: IAC SB LINEMODE SLC");
}
sprintf(s,"%c%c%c",tw->parsedat[i],SLC_NOSUPPORT,0);
#ifdef OPTS_DEBUG
sprintf(munger," %d SLC_NOSUPPORT 0",tw->parsedat[i]);
opts_debug_print(munger);
#endif
netwrite(tw->port,s,3);
}
else
continue;
}
// RFC 1184: If we get a response that is the same as the current setting, ignore it. Technically, we
// should check the value for a CANTCHANGE response to satisfy part 2 of Sec 5.5. However, since we
// advertised that key as CANTCHANGE in the first place, the server should not be changing it. This
// should be fixed later, however I don't see it causing big problems right now. - JMB 12/93
if (! ((((tw->parsedat[i+1] & SLC_LEVELBITS) == SLC_NOSUPPORT) && (tw->slc[tw->parsedat[i]] == -1))
|| (((tw->parsedat[i+1] & SLC_LEVELBITS) == SLC_CANTCHANGE) && (tw->slc[tw->parsedat[i]] != -1)))) {
// If we get to this point, the value sent to us doesn't agree with what we want.
if (!(tw->parsedat[i+1] & SLC_AWK)) {
if (!lmslcflag) {
lmslcflag = 1; // Do this only once
sprintf(s,"%c%c%c%c",IAC,TEL_SB,N_LINEMODE,L_SLC);
netwrite(tw->port,s,4);
opts_debug_print("SENT: IAC SB LINEMODE SLC");
}
if (tw->slc[tw->parsedat[i]]==-1)
{
sprintf(s,"%c%c%c",tw->parsedat[i],SLC_NOSUPPORT,0);
#ifdef OPTS_DEBUG
sprintf(munger," %s SLC_NOSUPPORT 0",LMoptions[tw->parsedat[i]]);
#endif
}
else
{
sprintf(s,"%c%c%c",tw->parsedat[i],SLC_CANTCHANGE,(char)tw->slc[tw->parsedat[i]]);
#ifdef OPTS_DEBUG
sprintf(munger," %s SLC_CANTCHANGE %d",LMoptions[tw->parsedat[i]],
(char)tw->slc[tw->parsedat[i]]);
#endif
}
#ifdef OPTS_DEBUG
opts_debug_print(munger);
#endif
netwrite(tw->port,s,3);
// 2.6b16.1 if (tw->parsedat[i+2]==IAC) i++;
}
}
}
if (lmslcflag) {
sprintf(s,"%c%c",IAC,TEL_SE);
netwrite(tw->port,s,2);
}
/* otherwise just exit */
}
break;
default:
#ifdef OPTS_DEBUG
sprintf(munger, "RECV: SB LINEMODE ?? (?? = %c)", tw->parsedat[1]);
opts_debug_print(munger);
#endif
break;
}
break;
/* end of all the new line-mode stuff */
default:
break;
}
} // substate == TEL_SE
orig=st;
tw->telstate=STNORM;
break;
default:
orig=st;
tw->telstate=STNORM;
break;
} // switch(substate)
}
break;
default:
tw->telstate = STNORM;
break;
} // switch(tw->telstate)
/*
* quick scan of the remaining string, skip chars while they are
* uninteresting
*/
if (tw->telstate == STNORM) {
/*
* skip along as fast as possible until an interesting character is found
*/
if (!tw->eightbit) { /* BYU 2.4.10 */
while (st < mark) { /* BYU 2.4.10 */
if (*st == IAC) /* BYU 2.4.10 */
break; /* BYU 2.4.10 */
else { /* BYU 2.4.10 */
*st &= 0x7f; /* BYU 2.4.10 */
if (*st == ESC || *st == GS) /* BYU 2.4.10 */
break; /* BYU 2.4.10 */
st++; /* BYU 2.4.10 */
} } /* BYU 2.4.10 */
} else /* BYU 2.4.10 */
while (st < mark && *st != ESC && *st < 255 && *st != GS) // MP: translation mod
st++; /* BYU 2.4.10 */
/*
* send the string where it belongs
*/
if (!tw->timing) {
if (tw->termstate == TEKTYPE) {
short i;
i = VGwrite( tw->curgraph,(char *) orig, st-orig); /* BYU LSC */
if (i < (st - orig)) {
detachGraphics(tw->curgraph);
st = orig + i;
}
}
else if (tw->termstate == RASTYPE) {
short i;
i= VRwrite((char *) orig, st-orig); /* BYU LSC */
if (i <(st-orig)) {
tw->termstate = VTEKTYPE;
st = orig +i; /* Next char to parse */
}
}
else
VSwrite( tw->vs,(char *) orig,st-orig); /* BYU LSC - send to virtual VT102 */
}
orig = st; /* forget what we have sent already */
if (st < mark)
switch (*st) {
case 255: /* telnet IAC */
tw->telstate = IACFOUND;
st++;
break;
case GS:
if (tw->telstate != GS) {
tw->telstate = GS;
}
else
tw->telstate = STNORM;
st++;
break;
case ESC: /* ESCape code */
if (st == mark-1 || *(st+1) == 12 || *(st+1) == '^' ) {
tw->telstate = ESCFOUND;
}
st++; /* strip or accept ESC char */
break;
default:
if (*st++ > 127) {
if (st==mark) /*new addition */
VSwrite(tw->vs,(char *) orig,1); /* BYU LSC */
}
break;
} // switch(*st)
} // tw->telstate == STNORM
} // while (st < mark)
} // tw->termstate != DUMBTYPE
} /* parse */
void SendNAWSinfo(WindRec *s, short horiz, short vert)
{
char blah[20];
unsigned char height, width;
height = vert & 0xff;
width = horiz & 0xff;
/* 931112, ragge, NADA, KTH, ugly patch to not send IAC as window size */
if(height == 0xFF) height = 0xFE;
if(width == 0xFF) width = 0xFE;
netpush (s->port);
/* NCSA: syntax for command is: IAC SB NAWS widthHI widthLO heightHI heightLO IAC SE */
netwrite(s->port,"\377\372\037\000",4);
sprintf(blah,"%c\000", width);
netwrite(s->port,blah,2);
sprintf(blah,"%c\377\360", height);
netwrite(s->port,blah,3);
opts_debug_print("SENT: IAC SB NAWS <data> IAC SE");
}
/*
* Implementation specific Kerberos routines
*/
/*
* net_write
*/
void net_write (struct WindRec *tw, char *buf, short length)
{
netpush(tw->port);
netwrite(tw->port, buf, length);
}
/*
* send_auth_opt
*/
void send_auth_opt (struct WindRec *tw)
{
unsigned char *cp, buf[30];
cp = buf;
if (tw->authenticate) {
sprintf((char *)cp, "%c%c%c", IAC, TEL_WILLTEL, OPT_AUTHENTICATION); /* will authenticate */
cp += 3;
(tw->myopts)[OPT_AUTHENTICATION-MHOPTS_BASE] = 1;
if (tw->encrypt) {
sprintf((char *)cp, "%c%c%c", IAC, TEL_WILLTEL, OPT_ENCRYPT); /* will encrypt */
cp += 3;
(tw->myopts)[OPT_ENCRYPT-MHOPTS_BASE] = 1;
}
netpush(tw->port);
netwrite(tw->port, buf, cp - buf);
}
}
void tn_sendsub (struct WindRec *tw, short code, short request, char *cp, short length)
{
long len;
unsigned char *src, *lp, *limit;
static char start[] = {IAC, TEL_SB, 0, 0};
static char end[] = {IAC, TEL_SE};
src = (unsigned char *)cp;
limit = src + length;
start[2] = code;
start[3] = request;
netpush(tw->port);
netwrite(tw->port, start, 4);
/*
* Transmit the buffer. IACs must be doubled
*/
if (*src == IAC) { /* check initial iac in buffer */
netpush(tw->port);
netwrite(tw->port, start, 1); /* IAC */
}
while (src < limit) {
lp = src+1; /* dont check first char */
while (lp < limit) { /* scan for IAC */
if (*lp == IAC)
break;
lp++;
}
len = lp - src;
if (lp < limit) /* if stopped on IAC */
len++; /* include IAC in xmit */
netpush(tw->port);
netwrite(tw->port, src, len);
src = lp; /* resume scanning */
}
netpush(tw->port);
netwrite(tw->port, end, 2);
}
/*
* getcname
* Return a pointer to the cannonical host name
*/
char *getcname (WindRec *tw)
{
char *cp;
static char *b, buf[100];
cp = 0;
if (tw->cannon[0])
cp = tw->cannon;
// Doing the following is bad because we disposed of our init params!
// else if ((*(*(ConnInitParams **)(tw->myInitParams))->session)->hostname)
// cp = (char *)(*(*(ConnInitParams **)(tw->myInitParams))->session)->hostname;
/* make a local copy to avoid locking handles */
if (cp) {
b = buf;
while (*cp)
*b++ = *cp++;
*b++ = '\0';
return buf;
}
return cp;
}
/*
* encryptStatechange
* Called by encrypt.c when the encryption state changes
*/
#define kOurHit 32
void encryptStatechange (struct WindRec *tw)
{
MyWDEFPatch(zoomDocProc , tw->wind, wDraw, kOurHit);
}
void DemangleLineMode(char *s, short mode)
{
#ifdef OPTS_DEBUG
short i;
for (i=0; i<5; i++) {
if (mode & (1 << i))
strcat(s, LMmodes[i]);
}
#endif
}
void DemangleLineModeShort(char *s, short mode)
{
#ifdef OPTS_DEBUG
short i;
for (i=0; i<5; i++) {
if (mode & (1 << i))
strcat(s, LMmodeBits[i]);
else
strcat(s," ");
}
#endif
}
#if 0 // Temp storage space - JMB 2.6b16.1
/* First check to see if we need to reply */
for (i=2;(tw->parsedat[i]!='\0') && (tw->parsedat[i]!=IAC); i+=3) {
if (!(tw->parsedat[i+1] & SLC_AWK)) break;
if ((unsigned char)(tw->parsedat[i+2])==IAC) i++;
}
/* if we do then send a reply */
if ((tw->parsedat[i]!=IAC) && (tw->parsedat[i]!='\0')) {
// sprintf(s,"%c%c%c%c",IAC,TEL_SB,N_LINEMODE,L_SLC);
// netwrite(tw->port,s,4);
// opts_debug_print("SENT: IAC SB LINEMODE SLC");
#ifdef NEWSLC
for (i=2; (tw->parsedat[i]!='\0') && (tw->parsedat[i]!=IAC); i+=3)
{
if (!(tw->parsedat[i+1] & SLC_AWK)) /* no response of ACK set */
{
if (tw->parsedat[i+1] != SLC_NOSUPPORT)
{
sprintf(s,"%c%c%c",tw->parsedat[i],SLC_NOSUPPORT,0);
#ifdef OPTS_DEBUG
sprintf(munger," %s NOSUPPORT 0",LMoptions[tw->parsedat[i]]);
#endif
}
else /* Acknowledge the No_Support case */
{
sprintf(s,"%c%c%c",tw->parsedat[i],SLC_AWK|SLC_NOSUPPORT,(char)0);
#ifdef OPTS_DEBUG
sprintf(munger," %s NOSUPPORT|AWK 0",LMoptions[tw->parsedat[i]]);
#endif
}
#ifdef OPTS_DEBUG
opts_debug_print(munger);
#endif
netwrite(tw->port,s,3);
}
if ((unsigned char)(tw->parsedat[i+2])==IAC) i++;
}
#else
for (i=2, lmslcflag=0; (tw->parsedat[i]!='\0') && (tw->parsedat[i]!=IAC); i+=3) {
// RFC 1184: If we get a response that is the same as the current setting, ignore it. Technically, we
// should check the value for a CANTCHANGE response to satisfy part 2 of Sec 5.5. However, since we
// advertised that key as CANTCHANGE in the first place, the server should not be changing it. This
// should be fixed later, however I don't see it causing big problems right now. - JMB 12/93
if (! ((((tw->parsedat[i+2] & SLC_LEVELBITS) == SLC_NOSUPPORT) && (tw->slc[tw->parsedat[i+1]] == -1))
|| (((tw->parsedat[i+2] & SLC_LEVELBITS) == SLC_CANTCHANGE) && (tw->slc[tw->parsedat[i+1]] != -1)))) {
// If we get to this point, the value sent to us doesn't agree with what we want.
if (!(tw->parsedat[i+1] & SLC_AWK)) {
if (!lmslcflag) {
lmslcflag = 1; // Do this only once
sprintf(s,"%c%c%c%c",IAC,TEL_SB,N_LINEMODE,L_SLC);
netwrite(tw->port,s,4);
opts_debug_print("SENT: IAC SB LINEMODE SLC");
}
if (tw->slc[tw->parsedat[i]]==-1)
{
sprintf(s,"%c%c%c",tw->parsedat[i],SLC_NOSUPPORT,0);
#ifdef OPTS_DEBUG
sprintf(munger," %s SLC_NOSUPPORT 0",LMoptions[tw->parsedat[i]]);
#endif
}
else
{
sprintf(s,"%c%c%c",tw->parsedat[i],SLC_CANTCHANGE,(char)tw->slc[tw->parsedat[i]]);
#ifdef OPTS_DEBUG
sprintf(munger," %s SLC_CANTCHANGE %d",LMoptions[tw->parsedat[i]],
(char)tw->slc[tw->parsedat[i]]);
#endif
}
#ifdef OPTS_DEBUG
opts_debug_print(munger);
#endif
netwrite(tw->port,s,3);
if (tw->parsedat[i+2]==IAC) i++;
}
}
}
#endif
if (lmslcflag) {
sprintf(s,"%c%c",IAC,TEL_SE);
netwrite(tw->port,s,2);
}
}
/* otherwise just exit */
}
break;
#endif